﻿#define _WIN32_WINNT 0x0600
#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h> // 包含inet_ntop所需的头文件
#include <iostream>
#include <chrono>
#include <iomanip>

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")

#define DEFAULT_IP "192.168.1.2"   // 请确保这是本机有效IP
#define DEFAULT_PORT 35001          // 监听端口
#define DEFAULT_BUFLEN 200

int main() {
    WSADATA wsaData;
    SOCKET ListenSocket = INVALID_SOCKET;
    int iResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        std::cerr << "WSAStartup failed: " << iResult << std::endl;
        return 1;
    }

    // 直接使用 sockaddr_in 结构而不是 getaddrinfo
    sockaddr_in serverAddr;
    ZeroMemory(&serverAddr, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(DEFAULT_PORT);

    // 使用 inet_pton 转换IP地址
    iResult = InetPton(AF_INET, TEXT(DEFAULT_IP), &serverAddr.sin_addr);
    if (iResult != 1) {
        std::cerr << "Invalid IP address: " << DEFAULT_IP << ". Error: " << WSAGetLastError() << std::endl;
        std::cerr << "Tip: You can try using INADDR_ANY to listen on all available interfaces." << std::endl;
        WSACleanup();
        return 1;
    }

    // 创建UDP套接字
    ListenSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (ListenSocket == INVALID_SOCKET) {
        std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }

    // 设置 SO_REUSEADDR 选项，允许地址重用[6](@ref)
    int optval = 1;
    if (setsockopt(ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(optval)) == SOCKET_ERROR) {
        std::cerr << "setsockopt failed with error: " << WSAGetLastError() << std::endl;
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // 绑定套接字到指定地址和端口
    iResult = bind(ListenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
    if (iResult == SOCKET_ERROR) {
        int errorCode = WSAGetLastError();
        std::cerr << "bind failed with error: " << errorCode << std::endl;

        // 提供更具体的错误信息
        switch (errorCode) {
        case WSAEADDRINUSE:
            std::cerr << "Port " << DEFAULT_PORT << " is already in use." << std::endl;
            break;
        case WSAEADDRNOTAVAIL:
            std::cerr << "IP address " << DEFAULT_IP << " is not available on this system." << std::endl;
            std::cerr << "Please check your network configuration or use INADDR_ANY instead." << std::endl;
            break;
        case WSAEACCES:
            std::cerr << "Access denied. Try running as administrator." << std::endl;
            break;
        default:
            break;
        }

        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    std::cout << "UDP Server is successfully listening on IP " << DEFAULT_IP << " port " << DEFAULT_PORT << "..." << std::endl;
    std::cout << "Press Ctrl+C to stop the server." << std::endl;

    while (true) {
        struct sockaddr_in clientAddr;
        int clientAddrLen = sizeof(clientAddr);

        iResult = recvfrom(ListenSocket, recvbuf, recvbuflen, 0, (struct sockaddr*)&clientAddr, &clientAddrLen);
        if (iResult == SOCKET_ERROR) {
            std::cerr << "recvfrom failed with error: " << WSAGetLastError() << std::endl;
            continue;
        }
        else if (iResult > 0) {
            auto now = std::chrono::system_clock::now();
            std::time_t now_time = std::chrono::system_clock::to_time_t(now);
            std::tm now_tm;
            localtime_s(&now_tm, &now_time);

            std::cout << "[" << std::put_time(&now_tm, "%Y-%m-%d %H:%M:%S") << "] ";
            std::cout << "Received " << iResult << " bytes from ";

            // 使用 inet_ntop 替代 inet_ntoa (解决弃用警告)[6,7](@ref)
            char clientIpStr[INET_ADDRSTRLEN];
            InetNtop(AF_INET, &(clientAddr.sin_addr), clientIpStr, INET_ADDRSTRLEN);
            std::cout << clientIpStr << ":" << ntohs(clientAddr.sin_port) << std::endl;

            // 显示接收到的数据
            std::cout << "Data: ";
            for (int i = 0; i < iResult; ++i) {
                if (isprint(static_cast<unsigned char>(recvbuf[i]))) {
                    std::cout << recvbuf[i];
                }
                else {
                    std::cout << ".";
                }
            }
            std::cout << std::endl;
            std::cout << "----------------------------------------" << std::endl;
        }
    }

    closesocket(ListenSocket);
    WSACleanup();
    return 0;
}